package com.easy.core.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;

import org.apache.commons.lang.StringUtils;

/**
 * 描述：properties文件操作，基本用法与jdk自带的类一致。
 * 		增加对中文的支持；
 * 		增加对注释的支持；
 * 		增加保存后排序不变。
 * 默认编码为utf-8，其他编码请指明。
 * @package com.easy.core.util
 * @class PropertiesUtil
 */
public class PropertiesUtil extends LinkedHashMap<String, Object>{
	private static final long serialVersionUID = 1L;
	
	protected PropertiesUtil defaults;

	public PropertiesUtil() {
		this(null);
	}

	public PropertiesUtil(PropertiesUtil defaults) {
		this.defaults = defaults;
	}

	public synchronized Object setProperty(String key, String value) {
		return setProperty(key, value, null);
	}
	
	public synchronized Object setProperty(String key, String value, String comment) {
		Object obj = super.get(key);
		if(obj != null && obj instanceof Element){
			Element e = (Element) obj;
			String oldValue = e.value;
			e.value = value;
			if(null != comment) e.comment = comment;
			return oldValue;
		}else put(key, new Element(key, value, comment));
		return null;
	}
	
	public Element getElement(String key){
		Object value = super.get(key);
		if(value instanceof Element) return (Element) value;
		if(value instanceof String) return new Element(key, (String)super.get(key), "");
		return null;
	}
	
	public Element getElement(String key, Element defaultValue){
		Element element = getElement(key);
		return null == element ? defaultValue : element;
	}
	
	public String getProperty(String key) {
		Object oval = (super.get(key) instanceof Element) ? ((Element)super.get(key)).value : null;
		String sval = (oval instanceof String) ? (String) oval : null;
		return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
	}

	public String getProperty(String key, String defaultValue) {
		String val = getProperty(key);
		return (val == null) ? defaultValue : val;
	}
	
	public boolean getBoolean(String key){
		String val = getProperty(key);
		if(StringUtils.isNotBlank(val)&&"true".equalsIgnoreCase(val.trim()))
			return true;
		else if(StringUtils.isNotBlank(val)&&"false".equalsIgnoreCase(val.trim())){
			return false;
		}else throw new TypeCastException("\""+val+"\" is not a Boolean type!");
	}
	
	public boolean getBoolean(String key, boolean defaultValue){
		String val = getProperty(key);
		if(StringUtils.isNotBlank(val)&&"true".equalsIgnoreCase(val.trim()))
			return true;
		else if(StringUtils.isNotBlank(val)&&"false".equalsIgnoreCase(val.trim())){
			return false;
		}else return defaultValue;
	}
	
	public int getInteger(String key){
		String val = getProperty(key);
		if(StringUtils.isNotBlank(val)&&val.trim().matches("[\\d]+")){
			try {
				return Integer.parseInt(val.trim());
			} catch (Exception e) {
				throw new TypeCastException("\""+val+"\" is not a Integer type!");
			}
		}else throw new TypeCastException("\""+val+"\" is not a Integer type!");
	}
	
	public int getInteger(String key, int defaultValue){
		String val = getProperty(key);
		if(StringUtils.isNotBlank(val)&&val.trim().matches("[\\d]+")){
			try {
				return Integer.parseInt(val.trim());
			} catch (Exception e) {
				return defaultValue;
			}
		}else return defaultValue;
	}
	
	/**
	 * 描述：载入属性文件配置，默认使用UTF-8字符集
	 */
	public synchronized void load(InputStream inStream) throws IOException {
		this.load(inStream, "UTF-8");
	}
	
	public synchronized void load(InputStream inStream, String charset) throws IOException {
		BufferedReader reader = null;
		if(null!=charset && !"".equals(charset.trim())) reader = new BufferedReader(new InputStreamReader(inStream, charset));
		else reader = new BufferedReader(new InputStreamReader(inStream));
		String line = "";
		StringBuffer comment = null;
		while ((line = reader.readLine()) != null) {
			if(0==line.length()||0<line.trim().length()&&'#'==line.trim().charAt(0)){
				if(null==comment) comment = new StringBuffer();
				else comment.append(System.getProperty("line.separator"));
				comment.append(line);
				continue;
			}
			int separator = line.indexOf('=');
			if(separator<0){
				if(0<line.length()){//删除utf8的bom标记
					line = line.substring(1);
				}
				if(null==comment) comment = new StringBuffer();
				else comment.append(System.getProperty("line.separator"));
				comment.append(line);
			}else{
				String key = line.substring(0, separator);
				String value = line.substring(separator+1);
				//if(null!=comment&&0<comment.length())comment.deleteCharAt(comment.length()-1);
				put(key, new Element(key, value, null!=comment?comment.toString():null));
				comment = null;
			}
		}
	}

	public synchronized void store(OutputStream out) throws IOException {
		store(out, null, "UTF-8");
	}
	
	public synchronized void store(OutputStream out, String charset) throws IOException {
		store(out, null, charset);
	}
	
	public synchronized void store(OutputStream out, String comments, String charset) throws IOException {
		BufferedWriter awriter = new BufferedWriter(new OutputStreamWriter(out, charset));
		if (comments != null){
			writeln(awriter, "#" + comments);
			writeln(awriter, "#" + new Date().toString());
		}
		for (Iterator<String> e = keySet().iterator(); e.hasNext();) {
			String key = (String) e.next();
			Object obj = get(key);
			Element el = obj instanceof Element ? (Element) obj : new Element(key,"","");
			if(null!=el.comment){
				if(0<el.comment.trim().length()&&!el.comment.trim().startsWith("#"))
					writeln(awriter, '#'+el.comment);
				else writeln(awriter, el.comment);
			}
			writeln(awriter, key + "=" + el.value);
		}
		awriter.flush();
	}

	private static void writeln(BufferedWriter bw, String s) throws IOException {
		bw.write(s);
		bw.newLine();
	}
	
	/**
	 * 描述:存储在MAP中的数据封装
	 */
	public class Element{
		public String key,value,comment;
		public Element(String key, String value, String comment){
			this.key = key;
			this.value = value;
			this.comment = comment;
		}
		public String getKey(){
			return key;
		}
		public String getValue(){
			return value;
		}
		public String getComment(){
			return comment;
		}
	}
	
	/**
	 * 描述:数据类型转换异常
	 */
	class TypeCastException extends RuntimeException {
		private static final long serialVersionUID = -6361456000166474744L;
		public TypeCastException(){
			super();
		}
		public TypeCastException(String s){
			super(s);
		}
	}
}
